import {
  canUse,
  isNull,
  PagedList,
  PageParams,
  isUndefined,
  numberToString,
  _pick,
  toString,
} from "mmb";
import * as store_spokesmanpb from "../grpc-client/service/store_spokesman_pb";
import {
  getBgsStoreSpokesmanOpSafely,
  getMetadata,
  getOptionsOfLight,
  wrapperGrpcError,
} from "../grpc-client/grpcAdapter";
import GrpcErrCode from "../grpc-client/grpcErrCode";
import { jsTimestampToPb, pbTimestampToJs } from "./helper";
import {
  StoreSpokesman,
  UpdateStoreSpokesmanParams,
  StoreSpokesmanCacheInfo,
  StoreSpokesmanWithStore,
  StoreSpokesmanWithUser,
} from "./storeDeclareTypes";
import { getCache, setCache, makeEntityKey } from "../proxy/redisProxy";

// 考虑用缓存
// export const checkStoreSpokesman = async (
//   userId: string,
//   storeSpokesmanId: string
// ) => {
//   const k = makeStoreSpokesmanCacheKey(storeSpokesmanId);
//   let cacheItem = await getStoreSpokesmanInfo(storeSpokesmanId);
//   if (isUndefined(cacheItem)) {
//     console.log(`not found spokesman:${storeSpokesmanId},${userId}`);
//     return false;
//   }
//   if (cacheItem.userId !== userId) {
//     console.log(`mismatch spokesman:${storeSpokesmanId},${userId}`);
//     return false;
//   }

//   return true;
// };

export const getStoreSpokesmanInfo = async (storeSpokesmanId: string) => {
  const k = makeStoreSpokesmanCacheKey(storeSpokesmanId);
  const cv = await getCache(k);
  let cacheItem: StoreSpokesmanCacheInfo | undefined = undefined;
  if (canUse(cv)) {
    console.log("checkStoreSpokesman use cached value");
    cacheItem = JSON.parse(cv!) as StoreSpokesmanCacheInfo;
  } else {
    console.log("checkStoreSpokesman use query");
    const brandSpokesman = await getStoreSpokesman(storeSpokesmanId);
    if (!isUndefined(brandSpokesman)) {
      cacheItem = _pick(
        brandSpokesman,
        "userId",
        "storeId"
      ) as StoreSpokesmanCacheInfo;
      await setCache(k, cacheItem); // replay=>OK
    }
  }
  return cacheItem;
};

export const getStoreSpokesmanInfoSafely = async (storeSpokesmanId: string) => {
  const storeSpokesmanInfo = await getStoreSpokesmanInfo(storeSpokesmanId);
  return storeSpokesmanInfo!;
};

/****************************************************************************************/
/*                                   store_spokesman entity                                 */
/****************************************************************************************/

const makeStoreSpokesmanCacheKey = makeEntityKey("store_spokesman");

const storeSpokesmanPbToObject = (
  pb: store_spokesmanpb.StoreSpokesmanEntity
): StoreSpokesman => {
  return {
    storeSpokesmanId: toString(pb.getId()),
    userId: toString(pb.getUserId()),
    storeId: toString(pb.getStoreId()),
    aliasName: pb.getAliasName(),
    became: pbTimestampToJs(pb.getBecame())!,
    remark: pb.getRemark(),
    endorseActivityCount: pb.getEndorseActivityCount(),
    saleAmount: pb.getSaleAmount(),
  };
};

/****************************************************************************************/
/*                                   store_spokesman cmd                                */
/****************************************************************************************/

export const updateStoreSpokesman = async ({
  storeSpokesmanId,
  aliasName,
  remark,
}: UpdateStoreSpokesmanParams): Promise<StoreSpokesman> => {
  const cl = getBgsStoreSpokesmanOpSafely();
  const req = new store_spokesmanpb.UpdateStoreSpokesmanRequest();

  req.setId(Number(storeSpokesmanId));
  if (!isUndefined(aliasName)) {
    req.setAliasName(aliasName);
  }
  if (!isUndefined(remark)) {
    req.setRemark(remark);
  }

  return new Promise((resolve, reject) => {
    cl.updateStoreSpokesman(
      req,
      getMetadata(),
      getOptionsOfLight(),
      (err, res) => {
        if (!isNull(err)) {
          reject(wrapperGrpcError(err.details));
          return;
        }
        const opRet = res.getOpRet()!;
        if (!opRet.getSuccess()) {
          reject(wrapperGrpcError(opRet.getMsg()));
          return;
        }
        resolve(storeSpokesmanPbToObject(res.getStoreSpokesman()!));
      }
    );
  });
};

/****************************************************************************************/
/*                                   store_spokesman query                              */
/****************************************************************************************/

export const getStoreSpokesman = async (
  storeWarehouseId: string
): Promise<StoreSpokesman | undefined> => {
  const cl = getBgsStoreSpokesmanOpSafely();
  const req = new store_spokesmanpb.GetStoreSpokesmanRequest();

  req.setId(Number(storeWarehouseId));

  return new Promise((resolve, reject) => {
    cl.getStoreSpokesman(
      req,
      getMetadata(),
      getOptionsOfLight(),
      (err, res) => {
        if (!isNull(err)) {
          reject(wrapperGrpcError(err.details));
          return;
        }
        const opRet = res.getOpRet()!;
        if (!opRet.getSuccess()) {
          if (opRet.getCode() === GrpcErrCode.NOT_FOUND) {
            resolve(undefined);
            return;
          } else {
            reject(wrapperGrpcError(opRet.getMsg()));
            return;
          }
        }
        resolve(storeSpokesmanPbToObject(res.getStoreSpokesman()!));
      }
    );
  });
};

export const listNormalStoreSpokesmansByStoreID = async (
  storeId: string,
  pager: PageParams
): Promise<PagedList<StoreSpokesman>> => {
  const cl = getBgsStoreSpokesmanOpSafely();
  const req = new store_spokesmanpb.ListNormalStoreSpokesmansByStoreIDRequest();

  req.setLimit(pager.limit);
  req.setOffset(pager.offset);
  req.setStoreId(Number(storeId));

  return new Promise((resolve, reject) => {
    cl.listNormalStoreSpokesmansByStoreID(
      req,
      getMetadata(),
      getOptionsOfLight(),
      (err, res) => {
        if (!isNull(err)) {
          reject(wrapperGrpcError(err.details));
          return;
        }
        const opRet = res.getOpRet()!;
        if (!opRet.getSuccess()) {
          reject(wrapperGrpcError(opRet.getMsg()));
          return;
        }
        const ret: PagedList<StoreSpokesman> = {
          total: 0,
          items: [],
        };
        ret.total = res.getTotal();
        ret.items = res.getStoreSpokesmansList().map(storeSpokesmanPbToObject);
        resolve(ret);
      }
    );
  });
};

/****************************************************************************************/
/*                                   store_spokesman joins entity                       */
/****************************************************************************************/

const storeSpokesmanWithStorePbToObject = (
  pb: store_spokesmanpb.StoreSpokesmanWithStoreEntity
): StoreSpokesmanWithStore => {
  return {
    // store_spokesman
    storeSpokesmanId: toString(pb.getId()),
    userId: toString(pb.getUserId()),
    storeId: toString(pb.getStoreId()),
    aliasName: pb.getAliasName(),
    became: pbTimestampToJs(pb.getBecame())!,
    remark: pb.getRemark(),
    endorseActivityCount: pb.getEndorseActivityCount(),
    saleAmount: pb.getSaleAmount(),

    // store
    storeName: pb.getStoreName(),
    storePic: pb.getStorePic(),
    storeFansCount: pb.getStoreFansCount(),
    storePublishActivityCount: pb.getStorePublishActivityCount(),
  };
};

const storeSpokesmanWithUserPbToObject = (
  pb: store_spokesmanpb.StoreSpokesmanWithUserEntity
): StoreSpokesmanWithUser => {
  return {
    // store_spokesman
    storeSpokesmanId: toString(pb.getId()),
    userId: toString(pb.getUserId()),
    storeId: toString(pb.getStoreId()),
    aliasName: pb.getAliasName(),
    became: pbTimestampToJs(pb.getBecame())!,
    remark: pb.getRemark(),
    endorseActivityCount: pb.getEndorseActivityCount(),
    saleAmount: pb.getSaleAmount(),

    // spokesman User_Info
    spokesmanUserNickName: pb.getSpokesmanUserNickName(),
    spokesmanUserPic: pb.getSpokesmanUserPic(),
    // user_stat
    fansCount: pb.getFansCount(),
  };
};

/****************************************************************************************/
/*                                   store_spokesman joins query                        */
/****************************************************************************************/

export const listNormalStoreSpokesmanWithStoresByUserID = async (
  userId: string,
  pager: PageParams
): Promise<PagedList<StoreSpokesmanWithStore>> => {
  const cl = getBgsStoreSpokesmanOpSafely();
  const req =
    new store_spokesmanpb.ListNormalStoreSpokesmanWithStoresByUserIDRequest();

  req.setLimit(pager.limit);
  req.setOffset(pager.offset);
  req.setUserId(Number(userId));

  return new Promise((resolve, reject) => {
    cl.listNormalStoreSpokesmanWithStoresByUserID(
      req,
      getMetadata(),
      getOptionsOfLight(),
      (err, res) => {
        if (!isNull(err)) {
          reject(wrapperGrpcError(err.details));
          return;
        }
        const opRet = res.getOpRet()!;
        if (!opRet.getSuccess()) {
          reject(wrapperGrpcError(opRet.getMsg()));
          return;
        }
        const ret: PagedList<StoreSpokesmanWithStore> = {
          total: 0,
          items: [],
        };
        ret.total = res.getTotal();
        ret.items = res
          .getStoreSpokesmanWithStoresList()
          .map((it) => storeSpokesmanWithStorePbToObject(it));
        resolve(ret);
      }
    );
  });
};

export interface ListNormalStoreSpokesmanWithUsersByStoreIDParam {
  storeId: string;
  keyword?: string;
}

export const listNormalStoreSpokesmanWithUsersByStoreID = async (
  { storeId, keyword }: ListNormalStoreSpokesmanWithUsersByStoreIDParam,
  pager: PageParams
): Promise<PagedList<StoreSpokesmanWithUser>> => {
  const cl = getBgsStoreSpokesmanOpSafely();
  const req =
    new store_spokesmanpb.ListNormalStoreSpokesmanWithUsersByStoreIDRequest();

  req.setLimit(pager.limit);
  req.setOffset(pager.offset);
  req.setTs(jsTimestampToPb(pager.ts));
  req.setStoreId(Number(storeId));
  if (!isUndefined(keyword)) {
    req.setKeyword(keyword);
  }

  return new Promise((resolve, reject) => {
    cl.listNormalStoreSpokesmanWithUsersByStoreID(
      req,
      getMetadata(),
      getOptionsOfLight(),
      (err, res) => {
        if (!isNull(err)) {
          reject(wrapperGrpcError(err.details));
          return;
        }
        const opRet = res.getOpRet()!;
        if (!opRet.getSuccess()) {
          reject(wrapperGrpcError(opRet.getMsg()));
          return;
        }
        const ret: PagedList<StoreSpokesmanWithUser> = {
          total: 0,
          items: [],
        };
        ret.total = res.getTotal();
        ret.items = res
          .getStoreSpokesmanWithUsersList()
          .map((it) => storeSpokesmanWithUserPbToObject(it));
        resolve(ret);
      }
    );
  });
};
